﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace ycdlib
{
	public interface CharReader : IDisposable
	{
		int Line { get; }
		int Col { get; }

		void Close();
		int Read();
	}

	class StringReader : CharReader
	{
		char[] buff;
		int idx;
		int col;
		int row;
		bool hasCR;

		#region プロパティ

		public int Line { get { return row; } }
		public int Col { get { return col; } }

		#endregion


		public StringReader ( string s )
		{
			if( !string.IsNullOrEmpty(s) )
				buff = s.ToCharArray();
			else
				buff = null;
			idx = 0;
			col = 1;
			row = 1;
			hasCR = false;
		}

		#region CharReader メンバ

		public void Close()
		{
			idx = 0;
			buff = null;
		}

		public int Read ()
		{
			int c = buff[idx];
			++idx;
			if( c==0x0d )
			{
				++row;
				col = 1;
				hasCR = true;
			}else
			{
				if( c==0x0a )
				{
					if( !hasCR )
					{
						++row;
					}
					col = 1;
				}else
				{
					++col;
				}
				hasCR = false;
			}
			return c;
		}

		#endregion

		#region IDisposable メンバ

		public void Dispose ()
		{
			buff = null;
		}

		#endregion
	}


	class FileReader : CharReader, IDisposable
	{
		FileStream fs;
		StreamReader sr;
		int col;
		int row;
		bool hasCR;

		#region プロパティ

		public int Line { get { return row; } }
		public int Col { get { return col; } }

		#endregion


		public FileReader ( string filename )
		{
			fs = new FileStream( filename, FileMode.Open, FileAccess.Read, FileShare.Read );
			sr = new StreamReader( fs );
			col = 1;
			row = 1;
			hasCR = false;
		}



		#region CharReader メンバ

		public void Close ()
		{
			sr.Close();
		}

		public int Read ()
		{
			int c = sr.Read();
			if( c==0x0d )
			{
				++row;
				col = 1;
				hasCR = true;
			}else
			{
				if( c==0x0a )
				{
					if( !hasCR )
					{
						++row;
					}
					col = 1;
				}else
				{
					++col;
				}
				hasCR = false;
			}
			return c;
		}

		#endregion

		#region IDisposable メンバ

		public void Dispose ()
		{
			sr.Dispose();
			fs.Dispose();
		}

		#endregion
	}
}
